package lib.image.compress;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.media.ExifInterface;
import android.util.Log;

import java.io.File;
import java.io.IOException;

/**
 * description: 工具类
 * created by Sabirjan on 2017/11/25
 */
public class ImageUtil {

    private ExifInterface srcExif;
    private String srcImg;
    //用于打印日志
    private static boolean isDebug = true;

    private static final String TAG = "ImageUtil";

    /**
     * 把图片转化为指定的ARGB8888格式
     *
     * @param bit 你想转化图片
     * @return
     */
    protected Bitmap changeARGB8888(Bitmap bit) {
        Log.d("图片压缩", "compress of native");
        if (bit.getConfig() != Bitmap.Config.ARGB_8888) {
            Bitmap result;

            result = Bitmap.createBitmap(bit.getWidth(), bit.getHeight(),
                    Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(result);
            Rect rect = new Rect(0, 0, bit.getWidth(), bit.getHeight());
            canvas.drawBitmap(bit, null, rect, null);

            return result;


        } else {
            return bit;
        }
    }


    private void e(String TAG, String description) {
        if (isDebug) {
            Log.e(TAG, description);
        }
    }

    /**
     * 同步质量压缩
     *
     * @param isUseHoffman                  是否使用哈夫曼编码
     * @param CompressionRatio              质量1-100    1是最低质量
     * @param outpath                       用哈夫曼压缩后文件保存路径
     * @param bitmap                        需要压缩的bitmap图片
     * @param onImageCompressChangeListener 回调 如果是子线程调用那么回调在子线程
     */
    private void syncCompressNative(final boolean isUseHoffman, final int CompressionRatio, final String outpath, final Bitmap bitmap, final OnImageCompressChangeListener onImageCompressChangeListener) {

        String file = outpath;

        final File temp = new File(file.trim().toLowerCase());
        try {

            if (temp.exists()) {
                temp.delete();
                Log.e("图片压缩", "文件名存在, 删除yizhi图片文件");
            }

            final boolean newFile = temp.createNewFile();
            Log.e("图片压缩", "创建历史图片文件 = " + newFile);

            Log.e("图片压缩", "主线程 ==> 压缩图片");
            nativecompress(isUseHoffman, bitmap, onImageCompressChangeListener, file, CompressionRatio);
        } catch (IOException e) {
            Log.e("图片压缩", e.getMessage(), e);
        }
    }

    /**
     * 异步质量压缩
     *
     * @param isUseHoffman     是否使用哈夫曼编码
     * @param CompressionRatio 质量1-100    1是最低质量
     * @param outpath          用哈夫曼压缩后文件保存路径
     * @param bitmap           需要压缩的bitmap图片
     */
    private void asynCompressNative(final boolean isUseHoffman, final int CompressionRatio, final String outpath, final Bitmap bitmap, final OnImageCompressChangeListener onImageCompressChangeListener) {

        final String file = outpath;

        final File temp = new File(file.trim().toLowerCase());
        try {

            if (temp.exists()) {
                temp.delete();
            }

            final boolean newFile = temp.createNewFile();
            Log.e("图片压缩", "创建历史图片文件 = " + newFile);

            new Thread() {
                @Override
                public void run() {
                    super.run();
                    Log.e("图片压缩", "分线程 ==> 压缩图片");
                    try {
                        nativecompress(isUseHoffman, bitmap, onImageCompressChangeListener, file, CompressionRatio);
                    } catch (Exception ex) {
                        if (onImageCompressChangeListener != null) {
                            onImageCompressChangeListener.onCompressError(-1, "压缩失败:" + ex.getMessage());
                        }
                    }
                }
            }.start();
        } catch (Exception e) {
            if (onImageCompressChangeListener != null) {
                onImageCompressChangeListener.onCompressError(-1, "压缩失败:" + e.getMessage());
            }
            Log.e("图片压缩", e.getMessage(), e);
        }
    }

    private void nativecompress(boolean isUseHoffman, Bitmap bitmap, OnImageCompressChangeListener onImageCompressChangeListener, String outpath, int CompressionRatio) {
        Bitmap bitmapBack = bitmap;
        if (bitmapBack == null) {
            e(TAG, "CompressQC==>>传入参数 bitmap 为空");
            if (onImageCompressChangeListener != null)
                onImageCompressChangeListener.onCompressError(-100, "传入参数 bitmap 为空");
            return;
        }
        //校验格式
        if (bitmapBack.getConfig() != Bitmap.Config.ARGB_8888) {
            bitmapBack = changeARGB8888(bitmapBack);
        }
        if (onImageCompressChangeListener != null) {
            onImageCompressChangeListener.onCompressStart();
        }

        ImageCompress.nativeLibJpegCompress(outpath, bitmapBack, CompressionRatio, isUseHoffman, onImageCompressChangeListener);
    }


    /**
     * 通过缩放图片像素来减少图片占用内存大小
     *
     * @param filePath
     * @return
     */
    protected Bitmap compressImage(String filePath, String outPath, OnImageCompressChangeListener onImageCompressChangeListener) {
        Bitmap bitmap = null;
        try {
            File file=new File(filePath);
            if(!file.exists())
            {
                if(onImageCompressChangeListener!=null)
                {
                    onImageCompressChangeListener.onCompressError(-1,"目标图片不存在");
                    return bitmap;
                }
            }
            if (Checker.isJPG(filePath)) {
                try {
                    this.srcExif = new ExifInterface(filePath);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //第一次采样
            BitmapFactory.Options options = new BitmapFactory.Options();
            //该属性设置为true只会加载图片的边框进来，并不会加载图片具体的像素点
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, options);
            compressPxOptoion(options);
            bitmap = BitmapFactory.decodeFile(filePath, options);
            bitmap = rotatingImage(bitmap);
            if (bitmap != null) {
                syncCompressNative(true, 50, outPath, bitmap, onImageCompressChangeListener);
            }
        } catch (Exception ex) {
            System.out.println("图片压缩失败....无法打开图片，错误原因如下:");
            ex.printStackTrace();
            if (onImageCompressChangeListener != null)
                onImageCompressChangeListener.onCompressError(-1, "压缩失败，出错:" + ex.getMessage());
        }

        return bitmap;
    }


    private Bitmap rotatingImage(Bitmap bitmap) {

        if (srcExif == null) return bitmap;

        Matrix matrix = new Matrix();
        int angle = 0;
        int orientation = srcExif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                angle = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                angle = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                angle = 270;
                break;
        }
        matrix.postRotate(angle);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    private int computeSize(int srcWidth, int srcHeight) {
        srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
        srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;
        int longSide = Math.max(srcWidth, srcHeight);
        int shortSide = Math.min(srcWidth, srcHeight);
        float scale = ((float) shortSide / longSide);
        if (scale <= 1 && scale > 0.5625) {

            if (longSide < 1664) {
                return 1;//压缩比例 2 的N 次方(次幂)来设置
            } else if (longSide >= 1664 && longSide < 4992) {
                return 2;
            } else if (longSide > 4992 && longSide < 10240) {
                return 4;
            } else {
                return longSide / 1280 == 0 ? 1 : longSide / 1280;
            }

        } else if (scale <= 0.5625 && scale > 0.5) {
            return longSide / 1280 == 0 ? 1 : longSide / 1280;
        } else {
            return (int) Math.ceil(longSide / (1280.0 / scale));
        }
    }

    private void compressPxOptoion(BitmapFactory.Options options) {
        //获得原图的宽和高
        int outWidth = options.outWidth;
        int outHeight = options.outHeight;
        //定义缩放比例
        int sampleSize = computeSize(outWidth, outHeight);
        /********************************************************************************************/
        //至此，第一次采样已经结束，我们已经成功的计算出了sampleSize的大小
        /********************************************************************************************/
        //二次采样开始
        //二次采样时我需要将图片加载出来显示，不能只加载图片的框架，因此inJustDecodeBounds属性要设置为false
        options.inJustDecodeBounds = false;
        //设置缩放比例
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    }
}
